# coding=utf-8

import web

import settings
import redirect
import utils

import models
from __init__ import UserSession, OAUTH_SUCCESS, OAUTH_REGISTER_SUCCESS
from sc import SC

from forms import subscribe_form
from controllers.projects.models import Departure

render = settings.FRONT_RENDER

class Unsubscribe(object):
    """
    退订
    """
    def GET(self):
        msg = None
        # 获取要退订的email
        email = web.input().get('email', None)
        if utils.is_email(email):
            # 判定email是否已经预订
            if not models.subscribed_by_email(email):
                msg = u'此邮箱未订阅“寻宝图每周特惠精选追踪”（%s）' % email
        else:
            msg = u'请从正确的路径进入。'
                
        return render.users.unsubscribe(email, msg)
    
    def POST(self):
        msg = None
        flag = 'failure_24.png'
        # 获取要退订的email
        email = web.input().get('email', None)
        if utils.is_email(email):
            # 判断email是否已经订阅
            if models.subscribed_by_email(email):
                # 退订
                if models.unsubscribe_by_email(email):
                    msg = u'退订成功，您不会再收到寻宝图的任何邮件了。'
                    flag = 'valid_24.png'
                    # 清除会话状态
                    web.ctx.user.clear_subscribed()
                else:
                    msg = u'退订失败，请稍后重试。'
            else:
                msg = u'此邮箱未订阅“寻宝图每周特惠精选追踪”（%s）' % email
        else:
            msg = u'请从正确的路径进入。'

        return render.users.unsubscribe(email, msg, flag)

class ResetPassword(object):
    """
    重置密码
    """
    def GET(self):
        secret = web.input().get('secret', None)
        if secret:
            # 带有密钥
            return self.render_reset(secret)
        else:
            return self.render()

    def POST(self):
        secret = web.input().get('secret', None)
        if secret:
            # 带有密钥
            return self.render_reset_post(secret)
        else:
            return self.render_post()

    def render_reset_post(self, secret):
        """处理重置密码"""
        email = self.auth_secret(secret)
        if email and utils.is_email(email):
            # 密钥有效
            form = web.input(pwd = None, pscwd = None)
            if not form.pwd:
                return self.render_reset(secret, '请输入密码。')
            if cmp(form.pwd, form.pscwd) != 0:
                return self.render_reset(secret, '密码与确认密码不一致。')

            # 重置密码
            models.reset_pwd_by_email(email, utils.md5(form.pwd))
            # 如果用户修改的密码和他设置的密码相同时
            # reset_pwd_by_email方法不会返回True
            # 所以这里不判断reset_pwd_by_email的结果了
            return self.render_reset(secret, success = True)

        # 超时了
        return render.users.reset_password(expire = True)

    def render_post(self):
        form = web.input(email = None)
        # 验证邮箱格式有效性
        if not utils.is_email(form.email):
            return self.render('邮箱格式错误。')
        # email是否存在
        if not models.exists_email(form.email):
            return self.render('此邮箱尚未注册。')

        # 生成并获取密令
        secret = self.generate_reset_secret(form.email)
        # 发送邮件
        if utils.service_mail(form.email
                , '找回密码'
                , '''
                    <p>亲爱的订阅会员，您好</p>
                    <p>此邮件应您找回密码的申请而发出，请点击以下链接重置密码：</p><br />
                    <p><a href="http://xunbaotu.com/reset-password?secret=%(secret)s" target="_blank">http://xunbaotu.com/reset-password?secret=%(secret)s</a></p>
                    <br />
                    <p>此邮件若不是应您的请求发出，请忽略它。</p>
                    <p>寻宝图 xunbaotu.com</p>
                ''' % {'secret': secret}):
            # 邮件成功发出
            return self.render(post_office = utils.post_office(form.email))
        else:
            # 邮件发送失败
            return self.render('邮件发送失败，请稍后重试。')

    def render_reset(self, secret, msg = None, success = False):
        """重置密码"""
        email = self.auth_secret(secret)
        if email and utils.is_email(email):
            if success:
                # 如果操作成功
                # 清除密钥cookie
                self.clear_reset_secret()
            # 内容有效
            return render.users.reset_password(msg, success)
        # 超时了
        # 跳转到首页？
        return render.users.reset_password(expire = True)

    def render(self, msg = None, post_office = None):
        """渲染默认视图"""
        return render.users.forgot_password(msg, post_office)

    def auth_secret(self, secret):
        """验证密钥的有效性"""
        # 获取cookie中的签名
        sign = utils.decrypt_cookie('_reset')
        if sign:
            sign = sign.split('|')
            if len(sign) == 2:
                if utils.cmp_i(self.generate_sign(secret), sign[0]) == 0:
                    # 第一层签名有效
                    if utils.cmp_i(self.generate_sign(sign[1]), secret) == 0:
                        # 第二层签名有效
                        # 将该email地址返回
                        return sign[1]

        return False

    def clear_reset_secret(self):
        web.setcookie('_reset', None)

    def generate_reset_secret(self, email):
        """生成重置密令，并返回一个md5码"""
        secret = self.generate_sign(email)
        # 二次加密密钥
        re_secret = self.generate_sign(secret)
        # 将用户邮箱加密保存到cookie中
        utils.encrypt_cookie('_reset', '%s|%s' % (re_secret, email,))
        # 返回密钥
        # 这个密钥作为参数发到用户的邮箱中
        return secret

    def generate_sign(self, email):
        """生成签名"""
        return utils.md5('tIaN|%s|Zhen' % email)

class Register(object):
    """
    用户注册
    """
    def GET(self):
        # 获取cookie中的临时信息
        cook = UserSession.resolve_reg_cookie()
        if not cook:
            redirect.home()
        # 
        return render.users.register_auth(cook, Departure.get_departs())

class SubscribeLogin(object):
    """
    订阅登录
    """
    def GET(self):
        return self.render()

    def POST(self):
        email = web.input(email = None).email
        if email and utils.is_email(email):
            # 判断email是否有效订阅
            #if models.subscribed_by_email(email):
            # 判断email是否注册
            usr = models.get_login_by_email(email)
            if usr:
                # 是有效订阅，记录订阅状态
                session = UserSession.current()
                # 记录订阅状态
                #session.save_subscribed(email)
                # 记录登录状态
                session.save_email_login(email, usr)
                # 如果用户是登录状态
                if session.logined:
                    # 尝试进行一次关联
                    models.related_subscribed(email, session.uid)
                # 成功，转向
                return self.redirect_authed()
            else:
                # Email 格式有效
                # 但是没有完成订阅操作
                return self.render(1)
        # email的格式都是乱输入的
        return self.render(2)

    def render(self, authr = 0):
        return render.users.subscribe_login_lite(authr)

    def redirect_authed(self):
        from_url = web.input().get('from', None)
        if not from_url:
            # 如果没有来访页
            # 跳转到特惠信息列表
            from_url = '/discounts'

        if '?' not in from_url:
            from_url += '?'

        # 转向
        # 因为本视图在弹出层中打开
        # 所以这里使用JS跳转
        return '<script type="text/javascript">top.location.href = "%sauthed=2";</script>' % from_url

class Subscribe(object):
    """
    订阅
    """
    def GET(self):
        ipt = web.input(auth = None, mode = None)
        # 是否处于验证模式
        if ipt.auth:
            return self.render_auth(ipt.auth)
        elif ipt.mode == 'lite':
            return self.render_lite()
        else:
            return self.render(subscribe_form())

    def render_lite(self):
        """渲染精简模式"""
        f = subscribe_form()
        return render.users.subscribe_lite(f
                , Departure.get_departs()
                , utils.urlencode(web.input().get('from', '')))

    def render_auth(self, auth):
        """
        渲染验证模式
        """
        # 通过签名获取等待确认的订阅请求
        req = models.get_subscribe_queue_by_sign(auth)
        if req:
            if req.status == 1:
                # 已经确认过了
                # 如果再确认，直接转向
                return self.redirect_authed(req)

            session = web.ctx.user
            # 这里可能会进行一次关联
            if req.uid <= 0:
                # 若请求没有和任何用户关联
                # 且用户验证时处于登录状态
                # 这里进行一次关联
                if session.logined:
                    req.uid = session.uid
                else:
                    # 用户未登录
                    # 这里用email尝试获取一次注册用户
                    req.uid = models.get_uid_by_email(req.email)

            # 没有确认，那么就开始确认了
            if models.active_subscribe(req):
                # 这里保存一次订阅状态
                session.save_subscribed(req.email)
                if req.uid <= 0:
                    # 如果当前订阅的会话没有与某个用户关联
                    # 那么这里执行一次注册操作
                    return self.subscribe_register(req)
                else:
                    # 如果已经和某用户关联
                    # 直接转向，不做其他处理了
                    # 激活成功，转向
                    return self.redirect_authed(req)

        # 如果是无效的
        # 直接跳转到首页，不给提示了
        return redirect.home()

    def subscribe_register(self, req):
        """匿名订阅确认后，自动注册"""
        if models.add_empty_user(req.email):
            # 添加一个空用户
            # 只有邮箱地址，无密码
            # 转向到密码重设
            return self.redirect_reset(req.email)

        # 如果添加失败
        return False

    def redirect_reset(self, email):
        """转向到重设密码"""
        rp = ResetPassword()
        return redirect.redirect('/reset-password'
                , secret = rp.generate_reset_secret(email)
                , authed = 1)

    
    def redirect_subscribed(self):
        """
        已经订阅过的转向
        """
        from_url = web.input().get('from', False)
        if from_url:
            return redirect.redirect(from_url, subscribed = 1)
        else:
            return redirect.discounts(subscribed = 1)

    def redirect_authed(self, req):
        """
        验证后的转向
        """
        if req.from_url:
            # 如果来源地址有效，转向到来源地址
            return redirect.redirect(req.from_url, authed = 1)
        else:
            # 如果来源地址无效，转向到特惠页列表
            return redirect.discounts(authed = 1)

    def render(self, form, note = None):
        session = UserSession.current()

        email = web.input().get('email', '')
        if email:
            # 初始化email控件
            form.email.value = email

        return render.users.subscribe(form, Departure.get_departs()
                , note)

    def POST(self):
        session = UserSession.current()
        # 用户不需要登录
        # 也能进行订阅
        f = subscribe_form()
        if f.validates():
            # 保存这个订阅状态
            # 现在无论用户是否确认邮件
            # 只要有订阅动作就能浏览特惠详情
            session.save_subscribed(f.email.value)
            # 验证通过
            if session.subscribed and session.email == f.email.value:
                # 如果用户有订阅会话
                # 判定客户端存储的email是否已经订阅完成
                # 如果已经订阅完成
                if models.subscribed_by_email(session.email):
                    # 转向到该去的页面
                    return self.redirect_subscribed()
            elif models.subscribed_by_email(f.email.value):
                # 判定用户提交的email是否已经处于订阅状态
                # 如果已经订阅
                # -以前在这里记录了订阅会话状态
                # -因为逻辑改变，不用在这里保存了
                session.save_subscribed(f.email.value)
                # 转向到该去的页面
                return self.redirect_subscribed()


            # 添加订阅
            # 除了记录用户内码、email、地区以外
            # 还应该记录用户的来源地址，方便确认后跳转
            # 没有就算了
            #sign = models.add_subscribe_queue(session.uid
            #        , f.email.value
            #        , f.depart.value
            #        , web.input().get('from', ''))
            # 发送确认邮件
            #utils.service_mail(f.email.value
            #        , '寻宝图订阅确认'
            #        , render.users.mail_subscribe_auth(sign))
            Subscribe.subscribe_request(session.uid
                    , f.email.value
                    , f.depart.value
                    , web.input().get('from', ''))

            mail_url = utils.post_office(f.email.value)
            # 订阅成功
            return render.users.subscribe(sub_email = mail_url)
        else:
            notes = []
            if not f.valid:
                for input in f.inputs:
                    if input.note:
                        notes.append('"%s":"%s"' % (input.name, input.note))
            return self.render(f, ','.join(notes))

    @staticmethod
    def subscribe_request(uid, email, depart, url):
        """添加订阅请求"""
        # 添加订阅
        # 除了记录用户内码、email、地区以外
        # 还应该记录用户的来源地址，方便确认后跳转
        # 没有就算了
        sign = models.add_subscribe_queue(uid
                , email
                , depart
                , url)
        # 发送确认邮件
        utils.service_mail(email
                , '寻宝图订阅确认'
                , render.users.mail_subscribe_auth(sign))

class Logout(object):
    """
    用户登出
    """
    def GET(self):
        web.ctx.user.logout()

class Login(object):
    """
    用户登录
    """
    def GET(self):
        ipt = web.input()
        # 获取视图模式
        mode = ipt.get('mode', '')
        # 选择性渲染视图
        if mode == 'lite':
            return self.render_lite(ipt)
        elif mode == 'auth':
            return self.render_auth(ipt)
        else:
            return self.render(ipt)

    def render(self, ipt, status = ''):
        """
        普通模式的登录页
        """
        return status

    def render_auth(self, ipt):
        """
        验证登录
        """
        # OAUTH 登录结果
        # 如果登录失败，将传递给self.render()方法
        status = ''
        session = UserSession.current()
        # 获取连接的类型
        sc_type = ipt.get('sc', None)
        if sc_type:
            sc = SC()
            # 连接类型有效
            # 尝试获取社交连接客户端实例
            sclient = sc.get(sc_type)
            # 获取OAuth响应关键参数
            code = sclient.get_response_code(ipt)
            # 如果是验证后返回
            if code:
                # 如果是验证后返回
                # 这里进行登录操作，记录各种需要记入cookie的信息
                status = session.oauth_save_login(code, sclient)
                # 登录成功啦
                if status == OAUTH_SUCCESS:
                    # 登录成功后
                    # 看用户是否有订阅会话
                    if session.subscribed and models.subscribed_by_email(session.email):
                        # 这里尝试关联一次订阅
                        models.related_subscribed(session.email
                                , session.uid)

                    url = ipt.get('url', None)
                    # 如果有返回地址
                    if url:
                        raise web.seeother(url)
                    else:
                        # 没有指定要返回的地址
                        # 返回到首页
                        raise web.seeother('/')
                elif status == OAUTH_REGISTER_SUCCESS:
                    # 第一次登录，进行注册
                    return redirect.redirect('/register', url = ipt.get('url', None))

        # 各种失败后，返回到登录页
        return self.render(ipt, status)

    def render_register(self, ipt):
        """注册/绑定帐号"""
        return render.users.register_auth()

    def render_lite(self, ipt):
        """
        渲染精简版的登录界面
        """
        #sc = SC()
        #sc.Sina.callback_url = '/login?mode=auth&url=%s' % urllib.quote(ipt.get('url', ''))
        #auth_url = sc.Sina.get_authorize_url()
        #return render.users.login_lite(utils.urlencode(ipt.get('url', '')))
        return render.users.register_lite(utils.urlencode(ipt.get('url', '')))
        #return render.users.login_lite(auth_url)


class SocialConnect(object):
    """
    社交连接
    """
    def GET(self, type):
        sc = SC();
        try:
            api = {
                    'sina':sc.Sina,
                    'tencent':sc.Tencent,
                }[type]
        except:
            api = None
        if api:
            api.callback_url = '/login?mode=auth'
            # 获取验证成功后的返回路径
            url = web.input().get('url', None)
            if url:
                api.callback_url += '&url=%s' % utils.urlencode(url)

            # 转向到验证地址
            raise web.seeother(api.get_authorize_url())

        return '500'
